package com.hengyue.system.service.impl;

import com.hengyue.common.utils.StringUtils;
import com.hengyue.exception.ServiceException;
import com.hengyue.system.domain.criteria.SysUserCriteria;
import com.hengyue.system.domain.entity.SysRole;
import com.hengyue.system.domain.entity.SysUser;
import com.hengyue.system.repository.SysRoleRepository;
import com.hengyue.system.service.ISysRoleService;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl implements ISysRoleService {

    private final SysRoleRepository roleRepository;

    private final JdbcTemplate jdbcTemplate;

    @Override
    public Page<SysRole> selectRolePageList(SysRole role, Pageable pageable) {
        Specification<SysRole> spec = getSpecification(role);
        return roleRepository.findAll(spec, pageable);
    }

    @Override
    public List<SysRole> selectRoleList(SysRole role) {
        Specification<SysRole> spec = getSpecification(role);
        return roleRepository.findAll(spec);
    }

    @Override
    public List<SysRole> selectRolesByUserId(Long userId) {
        return null;
    }

    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        return null;
    }

    @Override
    public List<SysRole> selectRoleAll() {
        Sort sort = Sort.by(Sort.Direction.ASC, "roleSort");
        return roleRepository.findAll(sort);
    }

    @Override
    public List<Long> selectRoleListByUserId(Long userId) {
        return null;
    }

    @Override
    public List<SysUser> selectAllocatedUserList(SysUserCriteria criteria, Pageable pageable) {
        Specification<SysRole> spec = (root, query, cb) -> {
            return null;
        };
        return null;
    }

    @Override
    public List<SysRole> selectUnassignedRolesByUserId(Long userId) {
        return roleRepository.findUnassignedRolesByUserId(userId);
    }

    @Override
    public SysRole selectRoleById(Long roleId) {
        return roleRepository.findById(roleId).orElseThrow(() -> new SecurityException("角色不存在"));
    }


    @Override
    public boolean isRoleCodeNotUnique(String code, Long id) {
        Long roleId = id == null ? -1L : id;
        return roleRepository.existsByCodeAndIdNot(code, roleId);
    }

    @Override
    public boolean isRoleNameNotUnique(String name, Long id) {
        Long roleId = id == null ? -1L : id;
        return roleRepository.existsByNameAndIdNot(name, roleId);
    }

    @Override
    public boolean isRoleKeyNotUnique(String roleKey, Long id) {
        Long roleId = id == null ? -1L : id;
        return roleRepository.existsByRoleKeyAndIdNot(roleKey, roleId);
    }

    // 校验角色是否允许操作，超级管理员角色不允许操作
    @Override
    public void checkRoleAllowed(Long id) {

        if (StringUtils.isNotNull(id) && isAdmin(id)) {
            throw new ServiceException("不允许操作超级管理员角色");
        }

    }

    @Override
    public void checkRoleDataScope(Long... roleIds) {

    }

    @Override
    public int countUserRoleByRoleId(Long roleId) {
        return 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertRole(SysRole role) {
        roleRepository.save(role);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(SysRole role) {
        try {
            roleRepository.save(role);
        } catch (DataIntegrityViolationException e) {
            throw new ServiceException("角色数据保存失败，可能存在重复数据");
        } catch (Exception e) {
            throw new ServiceException("角色保存失败：" + e.getMessage());
        }
    }

    @Override
    public void updateRoleStatus(SysRole role) {

    }

    @Override
    public int authDataScope(SysRole role) {
        return 0;
    }

    @Override
    public int deleteRoleById(Long roleId) {
        return 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRoleByIds(Long[] roleIds) {
        // 1. 先解除角色与菜单的关联关系
        for (Long roleId : roleIds) {
            SysRole role = roleRepository.findById(roleId)
                    .orElseThrow(() -> new ServiceException("角色不存在"));
            role.getMenus().clear(); // 清除关联的菜单集合
            roleRepository.save(role); // 保存解除关联后的角色
        }
        // 2. 批量删除角色
        roleRepository.deleteAllByIdInBatch(Arrays.asList(roleIds));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAuthUsers(Long roleId, Long[] userIds) {
      roleRepository.deleteUserRoleRelations(roleId, userIds);
    }

    @Override
    @Transactional
    public void insertAuthUsers(Long roleId, Long[] userIds) {
        // 检查角色是否存在
//        roleRepository.findById(roleId).orElseThrow(() -> new ServiceException("角色不存在"));

        if (userIds == null || userIds.length == 0) {
            return;
        }

        List<Long> userIdList = Arrays.asList(userIds);

        // 准备批量插入的数据
        List<Object[]> batchArgs = userIdList.stream()
                .map(userId -> new Object[]{roleId, userId})
                .collect(Collectors.toList());

        // 定义插入 SQL 语句
        String sql = "INSERT INTO user_role (role_id, user_id) VALUES (?, ?)";

        // 执行批量插入
        jdbcTemplate.batchUpdate(sql, batchArgs);

    }

    @Override
    public Set<String> getPermsByRoleIds(Set<Long> roleIds) {

        List<String> perms = roleRepository.findPermsByRoleId(roleIds);
        Set<String> permsSet = new HashSet<>();
        for (String perm : perms) {
            if (StringUtils.isNotEmpty(perm)) {
                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
            }
        }
        return permsSet;
    }

    private Specification<SysRole> getSpecification(SysRole role) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("delFlag"), "0"));
            if (role.getId() != null && role.getId() != 0) {
                predicates.add(cb.equal(root.get("id"), role.getId()));
            }
            if (StringUtils.isNotEmpty(role.getName())) {
                predicates.add(cb.like(root.get("name"), "%" + role.getName() + "%"));
            }
            if (StringUtils.isNotEmpty(role.getStatus())) {
                predicates.add(cb.equal(root.get("status"), role.getStatus()));
            }
            if (StringUtils.isNotEmpty(role.getRoleKey())) {
                predicates.add(cb.like(root.get("roleKey"), "%" + role.getRoleKey() + "%"));
            }
            query.orderBy(cb.asc(root.get("roleSort")));
            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    private boolean isAdmin(Long id) {
        return id != null && 1L == id;
    }

}
